/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.controller.manage;

import cn.ac.nercis.pes.community.component.cells.NumberTableCell;
import cn.ac.nercis.pes.community.component.cells.opreate.OperateTableCell;
import cn.ac.nercis.pes.community.component.controls.PesComboBox;
import cn.ac.nercis.pes.community.component.controls.PesTextField;
import cn.ac.nercis.pes.community.component.dialog.*;
import cn.ac.nercis.pes.community.controller.base.InitDataLoad;
import cn.ac.nercis.pes.community.mapper.manage.UserViewMapper;
import cn.ac.nercis.pes.community.model.vo.TableDataModel;
import cn.ac.nercis.pes.community.model.vo.manage.UserVO;
import cn.ac.nercis.pes.community.support.FXMLController;
import cn.ac.nercis.pes.community.utils.IconUtils;
import cn.ac.nercis.pes.model.dto.manage.RoleDTO;
import cn.ac.nercis.pes.model.dto.manage.UserDTO;
import cn.ac.nercis.pes.model.dto.manage.UserDetailDTO;
import cn.ac.nercis.pes.service.manage.RoleService;
import cn.ac.nercis.pes.service.manage.UserService;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 用户管理控制器
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@FXMLController
public class UserManageController implements Initializable, InitDataLoad {

    @FXML
    private TextField queryText;
    @FXML
    private Button searchButton;
    @FXML
    private Button addButton;
    @FXML
    private Pagination pagination;

    @FXML
    private TableView<UserDTO> tableView;
    @FXML
    private TableColumn<UserDTO,String> numberColumn;
    @FXML
    private TableColumn<UserDTO,String> nameColumn;
    @FXML
    private TableColumn<UserDTO,String> accountColumn;
    @FXML
    private TableColumn<UserDTO,String> mailColumn;
    @FXML
    private TableColumn<UserDTO,String> phoneColumn;
    @FXML
    private TableColumn<UserDTO,String> typeColumn;
    @FXML
    private TableColumn<UserDTO,String> roleNameColumn;
    @FXML
    private TableColumn<UserDTO,String> operateColumn;

    @FXML
    private VBox userDetailBox;
    @FXML
    private PesTextField usernameField;
    @FXML
    private PesTextField displayNameField;
    @FXML
    private PesTextField phoneField;
    @FXML
    private PesTextField mailField;
    @FXML
    private PesComboBox roleField;

    private PageDialog pageDialog;

    private final UserService userService;
    private final RoleService roleService;
    private final TableDataModel<UserDTO> dataModel = new TableDataModel<>();
    private final UserVO userDetailData = new UserVO();
    private final List<RoleDTO> roles = new ArrayList<>();

    @Autowired
    public UserManageController(UserService userService,
                                RoleService roleService) {
        this.userService = userService;
        this.roleService = roleService;
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        searchButton.setGraphic(IconUtils.getGlyph("search-icon","tool-button-icon"));
        addButton.setGraphic(IconUtils.getGlyph("add-button-icon","tool-button-icon"));

        numberColumn.setCellFactory(col-> new NumberTableCell<>(this.pagination));
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("displayName"));
        accountColumn.setCellValueFactory(new PropertyValueFactory<>("username"));
        mailColumn.setCellValueFactory(new PropertyValueFactory<>("email"));
        phoneColumn.setCellValueFactory(new PropertyValueFactory<>("phone"));
        typeColumn.setCellValueFactory(new PropertyValueFactory<>("type"));
        roleNameColumn.setCellValueFactory(new PropertyValueFactory<>("roleName"));
        operateColumn.setCellFactory(col->new OperateTableCell<>(tableView,
                this::onEditButtonClick,this::onDelButtonClick));

        tableView.setItems(new FilteredList<>(dataModel.bodyProperty(), p -> true));
        dataModel.selectedIndexProperty().bind(tableView.getSelectionModel().selectedIndexProperty());
        pagination.pageCountProperty().bind(dataModel.pageCountProperty());
        pagination.currentPageIndexProperty()
                .addListener((obj, oldValue, number) -> {
                    if(Objects.nonNull(number)){
                        query(number.intValue());
                    }
                });
        //新增、编辑用户控件初始化
        initUserDetailControl();
    }

    @Override
    public void initializeData() {
        this.onSearch();
    }

    @FXML
    public void onSearch(){
        query(0);
    }

    @FXML
    private void onCreate(){
        this.usernameField.setFieldDisable(false);
        pageDialog = PageDialog.builder()
                .withIcon("dialog-add-icon")
                .withTitle("新增用户")
                .withContent(this.userDetailBox)
                .build();
        //初始化验证信息
        resetValidation();
        //新增用户数据初始化
        initAddUserData();
        //弹出新增用户页面
        pageDialog.show(this::saveUser);
    }

    private void onEditButtonClick(MouseEvent event) {
        UserDTO selectedUser = dataModel.bodyProperty().get(dataModel.getSelectedIndex());
        if(Objects.nonNull(selectedUser.getWebServer()) && selectedUser.getWebServer()){
            MessageDialog.builder()
                    .withType(MessageType.FAIL).withMessage("当前用户为服务端用户不允许修改")
                    .build().show();
            return;
        }
        this.usernameField.setFieldDisable(true);
        pageDialog = PageDialog.builder()
                .withIcon("dialog-edit-icon")
                .withTitle("编辑用户")
                .withContent(this.userDetailBox)
                .build();
        //初始化验证信息
        resetValidation();
        //编辑用户数据初始化
        initModifyUserData(selectedUser);
        //弹出修改用户页面
        pageDialog.show(this::saveUser);
    }

    private void onDelButtonClick(MouseEvent event){
        UserDTO selectedUser = dataModel.bodyProperty().get(dataModel.getSelectedIndex());
        if(Objects.nonNull(selectedUser.getWebServer()) && selectedUser.getWebServer()){
            MessageDialog.builder()
                    .withType(MessageType.FAIL).withMessage("当前用户为服务端用户不允许删除")
                    .build().show();
            return;
        }
        AlertDialog alertDialog = AlertDialog.builder()
                .withMode(AlertMode.CONFIRM)
                .withType(AlertType.WARN)
                .withTitle("删除提示")
                .withContent("确认删除当前用户信息吗？")
                .build();
        alertDialog.show((confirm)->{
            if(!confirm){
                return;
            }
            deleteUser(selectedUser.getId());
        });
    }

    private void saveUser(){
        if(!validInput()){
            return;
        }
        UserDetailDTO userData = UserViewMapper.INSTANCE.toDTO(this.userDetailData);
        CompletableFuture.supplyAsync(()->userService.save(userData))
                .thenAccept(res->Platform.runLater(()->{
                    if(res.isSuccess()){
                        //更新表数据
                        this.query(0);
                        this.pageDialog.close();
                        MessageDialog.builder()
                                .withType(MessageType.SUCCESS).withMessage("保存成功")
                                .build().show();
                    }else{
                        MessageDialog.builder()
                                .withType(MessageType.FAIL).withMessage(res.getMsg())
                                .build().show();
                    }
                }));
    }

    private void deleteUser(final String userId){
        CompletableFuture.supplyAsync(()->userService.delete(userId))
                .thenAccept(res->Platform.runLater(()->{
                    if(res.isSuccess()){
                        //更新表数据
                        this.query(0);
                        MessageDialog.builder()
                                .withType(MessageType.SUCCESS).withMessage("删除成功")
                                .build().show();
                    }else{
                        MessageDialog.builder()
                                .withType(MessageType.FAIL).withMessage(res.getMsg())
                                .build().show();
                    }
                }));
    }

    private void initUserDetailControl(){
        //控件绑定到数据模型
        this.usernameField.textProperty().bindBidirectional(userDetailData.usernameProperty());
        this.displayNameField.textProperty().bindBidirectional(userDetailData.displayNameProperty());
        this.phoneField.textProperty().bindBidirectional(userDetailData.phoneProperty());
        this.mailField.textProperty().bindBidirectional(userDetailData.emailProperty());
        this.roleField.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            if(Objects.nonNull(newValue)){
                String selectRoleId =this.roles.stream()
                        .filter(r->StringUtils.equals(r.getDescription(),newValue))
                        .map(RoleDTO::getId)
                        .findFirst()
                        .orElse("");
                userDetailData.setRoleId(selectRoleId);
            }else{
                userDetailData.setRoleId("");
            }
        });
    }

    private boolean validInput(){
        return this.usernameField.validate() && this.displayNameField.validate();
    }

    private void resetValidation(){
        this.usernameField.resetValidation();
        this.displayNameField.resetValidation();
    }

    private void initAddUserData(){
        userDetailData.setId("");
        userDetailData.setUsername("");
        userDetailData.setDisplayName("");
        userDetailData.setPhone("");
        userDetailData.setEmail("");
        CompletableFuture.supplyAsync(this.roleService::findAll)
                .thenAccept(res->Platform.runLater(()->{
                    //加载角色列表
                    roleField.setItems(roleItems(res));
                    this.roles.stream()
                            .findFirst()
                            .ifPresent(r->{
                                userDetailData.setRoleId(r.getId());
                                roleField.getSelectionModel().select(r.getDescription());
                            });
                }));
    }

    private void initModifyUserData(UserDTO user){
        userDetailData.setId(user.getId());
        userDetailData.setUsername(user.getUsername());
        userDetailData.setDisplayName(user.getDisplayName());
        userDetailData.setPhone(user.getPhone());
        userDetailData.setEmail(user.getEmail());
        userDetailData.setRoleId(user.getRoleId());
        CompletableFuture.supplyAsync(this.roleService::findAll)
                .thenAccept(res->Platform.runLater(()->{
                    //加载角色列表
                    roleField.setItems(roleItems(res));
                    this.roles.stream().filter(r-> StringUtils.equals(r.getId(),user.getRoleId()))
                            .map(RoleDTO::getDescription)
                            .findFirst()
                            .ifPresent(roleField.getSelectionModel()::select);
                }));
    }

    private ObservableList<String> roleItems(List<RoleDTO> res){
        this.roles.clear();
        this.roles.addAll(res);
        return FXCollections.observableList(this.roles.stream().map(RoleDTO::getDescription).collect(Collectors.toList()));
    }

    private void query(Integer page){
        String query = StringUtils.trim(queryText.getText());
        CompletableFuture.supplyAsync(()->this.userService.findAll(query,query, PageRequest.of(page,TableDataModel.LIMIT)))
                .thenAccept(res-> Platform.runLater(()->{
                    dataModel.bodyProperty().clear();
                    List<UserDTO> users = res.getContent();
                    dataModel.setPageCount(res.getTotalPages());
                    dataModel.bodyProperty().addAll(users);
                }));
    }
}